Skip to content

Optimize Runtime Performance ​

1. Runtime Performance Overview ​

Unity WebGL is a technical solution with WebAssembly (WASM) + WebGL at its core. Runtime performance greatly affects the game content and gameplay it can support.

This article mainly introduces the performance differences between Unity WebGL and ordinary H5 games based on JS engines, as well as native APP mobile games, caused by their technology stacks, and the performance differences between different system platforms (Android, iOS, Windows PC). It then describes the best performance optimization tools and common optimization techniques.

Runtime Performance Differences: Unity WebGL VS APP ​

  • CPU Performance Difference

Unity WebGL runs in a browser-like environment in the form of a WASM virtual machine, so CPU computing power is limited by the execution efficiency of the virtual machine.

Unity WebGL currently does not support multithreading, so some modules such as AI, animation, and rendering cannot benefit from multithreaded acceleration.

This is the most important factor causing the performance gap between Unity WebGL and APPs. Generally, Unity WebGL is 1/3 of the performance of an APP mobile game, so developers should pay special attention to CPU-side performance bottlenecks.

You can learn about the performance differences between different Unity modules and mobile APPs via Benchmarking Unity performance in WebGL.

  • GPU Performance Difference

Unity renders using the WebGL API, where WebGL1.0 is equivalent to OpenGLES2.0 and WebGL2.0 is equivalent to OpenGLES3.0.

WebGL wraps the native rendering API with a small amount of overhead, but its basic rendering capabilities are close to those of a native APP.

Rendering features such as GPU Instancing and SRP Batcher require WebGL2.0. (Note that when an APP mobile game uses these features, the gap will widen further if WebGL2.0 is not enabled in the minigame.)

Runtime Differences: WASM VS JS ​

WASM is a strongly-typed language, which allows JIT optimization to more accurately predict runtime types, so compared with JS it can reach the peak after JIT instruction optimization more quickly. Generally, WASM ~= 1.5 * JS, i.e., more than 150% of the runtime efficiency of JS.

The Unity engine currently is not well optimized for the browser environment (for example, the frequency of mutual calls between WASM and host interfaces, and trimming of unnecessary code paths), so it is relatively bloated, and in some usage scenarios it is actually not as lightweight as JS.

Therefore, the two cannot simply be compared by language computing power in actual use; it should be based on actual game measurements.

Performance Differences Between System Platforms

Android and Windows PC use V8 as the WASM virtual machine core and support JIT, so under the same computing power the performance of the two is similar. But note that mobile platforms have worse heat dissipation, so they are more demanding on performance.

iOS defaults to normal mode, which does not support JIT and can be used for hyper-casual games; for mid-core and hardcore games, it is recommended to enable iOS High Performance mode to support JIT, but this mode requires more effort to tune, especially regarding startup heating and memory.

2. Optimization Goals ​

Since Unity WebGL performance cannot fully reach the level of a native APP, developers need to establish different minimum device requirements and smoothness standards based on different game categories. Recommendations:

Light casual games should ensure more than 30fps on low-end devices, and need to pay special attention to device compatibility (you can use the minigame cloud testing to obtain a compatibility report) to achieve coverage of acquired users.

Mid-core and hardcore games should ensure more than 40fps on mid- and high-end devices with uncapped frame rate, and in actual runtime the frame rate can be capped at 30 to maintain heat levels for long idle running.

For detailed benchmark devices and performance requirements, refer to the performance evaluation standard. The platform has no strict performance requirements for going live; developers need to formulate them based on their own game's commercialization requirements.

3. Optimization Tools ​

3.1 Unity Profiler ​

The Unity Profiler works by having the Unity Editor listen on a fixed port; the Unity WebGL game connects via WebSocket at runtime and periodically sends performance data.

  • The tool needs the development mode enabled, which has a large impact on performance.

  • It can obtain function hotspots, memory, and module reporting data (such as physics, animation, etc.).

  • It is not very stable; some versions may fail to connect.

  • The memory data is inaccurate and cannot reflect actual usage. For memory tools, please refer to Optimize Unity WebGL memory.

4. Optimization Techniques ​

  • Configuration Loading and Protocol Parsing

Do not use XML or JSON to parse large files, especially during the game startup phase; string-type parsers consume a lot of CPU computing power and generate GC. For example, in large games using Addressable, the catalog file often exceeds 10MB, causing slow parsing that affects startup speed; in this case you should use other resource management such as AssetBundle to reduce the size of the resource index file. Similarly, avoid this kind of CPU consumption during gameplay as much as possible.

  • Lua Performance

Lua in the Unity WebGL environment does not support JIT, so avoid using it for heavy logic. You can use the Android CPU Profiler for performance tuning to check the proportion of time spent on Lua.

  • Physics Performance

Please refer to the document Optimize physics performance, and appropriately adjust Fixed Timestep and Maximum Allowed Timestep to reduce the computation frequency.

  • Instantiation

Since Unity WebGL is a single-threaded model, long-running CPU computations will affect the frame rate. Common cases are AssetBundle loading and Prefab instantiation; loading across frames through optimized logic can greatly improve the game experience.

  • Limit Frame Rate

Limiting the frame rate helps reduce device heating and increase game session length; it is recommended for games that are not sensitive to frame rate. You can use Application.targetFramerate to cap the frame rate; when the frame rate is 15/30/60, raf slicing is used, and other values use a timer for control.

  • Limit Resolution

Limiting the resolution reduces device consumption at the cost of some visual quality. On the minigame platform, please do not use Unity's SetResulution and similar interfaces to change the resolution; use DevicePixelRatio for control (only supported on iOS and Android).

  • Use Compressed Textures

When compressed textures are not supported, textures need to be soft-decoded to RGB/RGBA32 on the CPU, causing huge CPU and memory consumption. This behavior at runtime causes noticeable frame rate stutters, so it is recommended to use texture compression optimization.

  • WebGL2.0 Notes

Please refer to the WebGL2.0 rendering support notes.

  • Reduce Drawcalls

A large number of DCs causes very large CPU pressure. When too many objects are rendered in a scene, appropriate measures should be taken to reduce Drawcalls.

For the standard render pipeline, use Static Batch appropriately to reduce DCs. When WebGL2.0 can be enabled, use GPU Instancing. Set LOD and visible ranges whenever possible to reduce rendered objects.

  • Use SRP Batcher The SRP Batcher for Unity WebGL requires two prerequisites: Unity 2021 or above + WebGL2.0.